%{

#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <stdlib.h>

#include "structs.c"
//#include "app.c"

#define DEBUG 1

%}

%union{
	struct argument_list *arg_list;
	struct line_code *line_code;
	struct block_code *block_code;
	int type_id;
	int it;
	float fl;
	char *name;
}


%token <name> INCLUDE_GL
%token <name> INCLUDE_LC
%token <name> NAME
%token <name> MACRO

%token <name> ASM
%token <name> AUTO
%token <name> BOOL
%token <name> BREAK
%token <name> CASE
%token <name> CATCH
%token <name> CHAR
%token <name> CLASS
%token <name> CONST
%token <name> CONTINUE
%token <name> DEFAULT
%token <name> DELETE
%token <name> DO
%token <name> WHILE
%token <name> DOUBLE
%token <name> ELSE
%token <name> ENUM
%token <name> EXTERN
%token <name> FLOAT
%token <name> FOR
%token <name> FRIEND
%token <name> GOTO
%token <name> IF
%token <name> INLINE
%token <name> INT
%token <name> LONG
%token <name> NAMESPACE
%token <name> NEW
%token <name> OPERATOR
%token <name> PRIVATE
%token <name> PROTECTED
%token <name> PUBLIC
%token <name> REGISTER
%token <name> RETURN
%token <name> SHORT
%token <name> SIGNED
%token <name> SIZEOF
%token <name> STATIC
%token <name> STRUCT
%token <name> SWITCH
%token <name> TEMPLATE
%token <name> THIS
%token <name> THROW
%token <name> TRY
%token <name> TYPEDEF
%token <name> UNION
%token <name> UNSIGNED
%token <name> USING
%token <name> VIRTUAL
%token <name> VOID
%token <name> VOLATILE
%token <name> WCHAR_T

%token <name> PLUS
%token <name> MINUS

%token <name> WHITE

%token <name> CODE_LINE

%type <name> TYPE
%type <it> DIRECTIVE
%type <arg_list> ARGUMENTS_LIST
%type <block_code> CODE_BLOCK_NORMAL

%type <line_code> CODE_LINES

%type <block_code> CODE_BLOCK

%type <block_code> IF_INSTR
%type <block_code> ELSE_IF

/*
%type <it> FUNCTION
%type <name> EXPRESION
%type <name> CODE_LINE
*/
%%

/* gdy na wejsciu pojawi sie symbol terminalny NUM zostanie wywolana ponizsza akcja */

input: 
| input FUNCTION 
| input DIRECTIVE 

FUNCTION: TYPE NAME '(' ARGUMENTS_LIST ')' CODE_BLOCK_NORMAL  {
	
	#if DEBUG
		printf("FUNCTION: TYPE NAME '(' ARGUMENTS_LIST ')' CODE_BLOCK_NORMAL \tDodawanie funkcji typu %s nazwa %s\n", $1, $2);
	#endif

	add_function( $1 , $2 , $4 , $6 );
}


CODE_BLOCK_NORMAL: '{' '}'
{

	#if DEBUG
		printf("CODE_BLOCK_NORMAL: '{' '}'\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 0;
	$$->code = 0;
	$$->inner= 0;
	$$->next = 0;

}
| '{' CODE_LINES '}'
{
	#if DEBUG
		printf("CODE_BLOCK_NORMAL: '{' CODE_LINES '}'\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 0;
	$$->code = $2;
	$$->inner= 0;
	$$->next = 0;
} 
| '{' CODE_LINES  CODE_BLOCK '}'
{
	#if DEBUG
		printf("CODE_BLOCK_NORMAL: '{' CODE_LINES  CODE_BLOCK '}'\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 0;
	$$->code = $2;
	$$->inner= $3;
	$$->next = 0;
} 

CODE_BLOCK: 
/* EMPTY */ 
{ 
	#if DEBUG
		printf("CODE_BLOCK: /* EMPTY */\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = -1;
	$$->code = 0;
	$$->inner= 0;
	$$->next = 0;
}
| CODE_LINES
{ 
	#if DEBUG
		printf("CODE_BLOCK: CODE_LINES\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = -2;
	$$->code = $1;
	$$->inner= 0;
	$$->next = 0;
}
|  CODE_BLOCK_NORMAL CODE_BLOCK 
{
	#if DEBUG
		printf("CODE_BLOCK: CODE_BLOCK_NORMAL CODE_BLOCK \n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 0;
	$$->code = $1;
	$$->next = $2;
	$$->inner= 0;
}
| IF_INSTR CODE_BLOCK
{
	#if DEBUG
		printf("CODE_BLOCK: IF_INSTR CODE_BLOCK Dodawanie bloku kodu typ IF_INSTR CODE_BLOCK  \n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 1;
	$$->code = 0;
	$$->inner= $1;
	$$->next = $2;
}
| IF_INSTR CODE_LINES
{
	#if DEBUG
		printf("CODE_BLOCK: IF_INSTR CODE_BLOCK Dodawanie bloku kodu typ IF_INSTR CODE_BLOCK  !!!!!!!!!!!!!!\n");
	#endif

	$$ = malloc(sizeof(struct block_code)); 
	$$->type = 1;
	$$->code = 0;
	$$->inner= $1;
	$$->next = $2;
}

IF_INSTR: 
IF CODE_BLOCK_NORMAL ELSE_IF
{
	#if DEBUG
		printf("IF_INSTR: IF CODE_BLOCK_NORMAL ELSE_IF Dodawanie bloku kodu typ IF_INSTR CODE_BLOCK  \n");
	#endif

	$$ = $2;
	$2->type = 1;//zmiana na if
	$2->next = $3;
	$2->exp = $1;
	
	//$$->code = 0;//$1;//wyrazenie w ifie
	//$$->inner= $5;
	//$$->next = $7;
}


ELSE_IF: 
ELSE CODE_BLOCK_NORMAL
{
	#if DEBUG
		printf("ELSE_IF: ELSE CODE_BLOCK_NORMAL Dodawanie bloku kodu typ ELSE IF\n");
	#endif

	$$ = $2;
	$$->type = 3;//else
	$$->code = 0;
	//$$->inner= $3;
	//$$->next = 0;

}
| ELSE IF CODE_BLOCK_NORMAL 
{
	#if DEBUG
		printf("ELSE_IF: ELSE IF CODE_BLOCK_NORMAL\n");
	#endif

	$$ = $3;
	$$->exp = $2;
	$$->type = 2;//else if
}
| ELSE IF CODE_BLOCK_NORMAL ELSE_IF
{
	#if DEBUG
		printf("ELSE_IF: ELSE IF CODE_BLOCK_NORMAL ELSE_IF \n");
	#endif

	$$ = $3;
	$$->exp = $2;
	$$->type = 2;//else if
	$$->next = $4;
}


ARGUMENTS_LIST:
/* EMPTY */     
{ 
	#if DEBUG
		printf("ARGUMENTS_LIST:\n");
	#endif

	$$ = 0; 

}
| TYPE NAME   
{ 
	#if DEBUG
		printf("ARGUMENTS_LIST: TYPE NAME %s %s\n", $1, $2);
	#endif

	$$ = malloc( sizeof(struct argument_list));
	$$->type_name = $1;
	$$->name = $2;
	$$->next = 0;

}
| ARGUMENTS_LIST ',' TYPE NAME  
{ 
	#if DEBUG
		printf("ARGUMENTS_LIST: ARGUMENTS_LIST ',' TYPE NAME %s %s \n", $3, $4);
	#endif

	$$ = malloc( sizeof(struct argument_list));
	$$->type_name = $3;
	$$->name = $4;
	$$->next = $1;
};

CODE_LINES:
CODE_LINES CODE_LINE 
{ 
	#if DEBUG
		printf("CODE_LINES: CODE_LINES CODE_LINE %s\n",$2);
	#endif

	$$ = malloc( sizeof( struct line_code));  
	$$->text = $2;
	$$->next = $1;

}
| CODE_LINE 
{
	#if DEBUG
		printf("CODE_LINE  %s \n", $1);
	#endif

	$$ = malloc( sizeof( struct line_code));  
	$$->text = $1;
	$$->next = 0;
}

TYPE: VOID                  { $$ = $1; }
| BOOL                  { $$ = $1; }
| CHAR                  { $$ = $1; }
| INT                   { $$ = $1; }
| UNSIGNED INT          { $$ = $1; }
| SIGNED INT            { $$ = $1; }
| UNSIGNED SHORT INT    { $$ = $1; }
| SIGNED SHORT INT      { $$ = $1; }
| SHORT INT             { $$ = $1; }
| SIGNED LONG INT       { $$ = $1; }
| UNSIGNED LONG INT     { $$ = $1; }
| LONG INT              { $$ = $1; }
| LONG LONG INT         { $$ = $1; }
| UNSIGNED LONG LONG INT{ $$ = $1; }
| DOUBLE                { $$ = $1; }
| LONG DOUBLE           { $$ = $1; }
| FLOAT                 { $$ = $1; }
| LONG                  { $$ = $1; }
| SHORT                 { $$ = $1; }
| NAME                  { $$ = $1; };


DIRECTIVE:    INCLUDE_LC { printf("rozpoznano include lokalny %s\n", $1); }
| INCLUDE_GL { printf("rozpoznano include globalny %s\n", $1 ); }

/* do przekazywania wartosci semantycznych pomiedzy regulami sluza tzw. pseudozmienne; 
   akcja moze zwrocic wartosc przez podstawienia pseudozmiennej $$;
   pseudozmiennej $1 uzyto w przykladzie, aby wypisac wartosc tokenu NUM */

%%
#include "lex.yy.c"
#include <stdlib.h>

main(int argc, char *argv[]) {

	yyparse(); 

	struct function_list *temp = g_function_list;

	printf("Koniec Parsowania.\nPrzechodzenie w dół po wszystkich funkcjach:\n");

	while(temp)
	{
		printf("Funkcja o nazwie %s i zwracanym typie: %s\n",temp->name,temp->return_type);
		struct argument_list *wsk = temp->arg_list;
		if(wsk == 0)
		{
			printf("\tBrak Argumentów:\n");
		}
		else
		{
			printf("\tArgumenty:\n");

			while(wsk)
			{
				printf("\t\tArgument %s o typie %s\n",wsk->name, wsk->type_name);
				wsk = wsk->next;
			}
		}

		block_print(temp->block,0);

		temp = temp->next;
	}
	//run(argc, argv, g_function_list);
}


/* gdy funkcja yyparse wykryje blad wywoluje funkcje yyerror */
int yyerror(char *s) {

	printf("blad: %s\n", s); 
}
